package com.jcl.tree.utils;

import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import org.springframework.util.StringUtils;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author 朝花不迟暮
 * @version 1.0
 * @date 2021/5/12 21:26
 */
public class ZipUtil
{
    /**
     * 分卷压缩
     *
     * @param srcFiles 要压缩的文件绝对路径列表（支持多个文件的合并压缩）
     * @param destFile 要压缩的zip文件名
     * @param pwd      压缩密码
     * @param fileSize 分卷大小
     * @return 压缩文件路径（如分卷会返回以 "," 分隔的文件路径列表）
     * @throws ZipException
     */
    public static String zip(List<String> srcFiles, String destFile, String pwd, long fileSize) throws ZipException
    {
        String zipFiles = null;
        File tmpFile = new File(destFile);
        if (tmpFile.exists())
        {
            tmpFile.delete();
        }

        ZipFile zipFile = new ZipFile(destFile);

        ArrayList<File> filesToAdd = new ArrayList<>();
        if (srcFiles != null && srcFiles.size() > 0)
        {
            for (String srcFile : srcFiles)
            {
                filesToAdd.add(new File(srcFile));
            }

            ZipParameters parameters = new ZipParameters();
            if (StringUtils.hasLength(pwd))
            {
                parameters.setEncryptFiles(true);
                parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD);
                parameters.setPassword(pwd.toCharArray());
            }
            parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);

            parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);

            //未指定则设置为512KB
            if (fileSize == 0)
            {
                fileSize = 1024 * 1024 * 3;
            }
            zipFile.createZipFile(filesToAdd, parameters, true, fileSize);

            @SuppressWarnings("unchecked")
            ArrayList<String> zipList = zipFile.getSplitZipFiles();
            if (zipList != null && zipList.size() > 0)
            {
                String surFix = ".z010";
                String surFixReplace = ".z10";
                for (int i = 0; i < zipList.size(); i++)
                {//针对第10个包的文件名做特殊处理
                    String file = zipList.get(i).trim();
                    int length = file.length();
                    String surFixTmp = file.substring(length - 5, length);
                    if (surFix.equals(surFixTmp))
                    {
                        file = file.replace(surFix, surFixReplace);
                    }
                    zipList.set(i, file);
                }
                String[] zipArray = new String[zipList.size()];
                zipList.toArray(zipArray);
                zipFiles = Arrays.toString(zipArray);

                int length = zipFiles.length();
                zipFiles = zipFiles.substring(1, length - 1);
            }
        }
        return zipFiles;
    }


    /**
     * 解压缩(支持分卷压缩解压)
     *
     * @param zipFilePath 指定的ZIP压缩文件 路径
     * @param dest        解压目录
     * @param pwd         ZIP文件的密码 。需要解压密码时必须传入，否则传入null即可
     * @return 解压后文件名数组
     * @throws ZipException 压缩文件有损坏或者解压缩失败抛出
     */
    @SuppressWarnings("unchecked")
    public static String[] unzip(String zipFilePath, String dest, String pwd) throws ZipException
    {
        File zipFile = new File(zipFilePath);
        net.lingala.zip4j.core.ZipFile zFile = new net.lingala.zip4j.core.ZipFile(zipFile);
        zFile.setFileNameCharset("GBK");
        if (!zFile.isValidZipFile())
        {
            throw new ZipException("压缩文件不合法,可能被损坏!");
        }

        File destDir = new File(dest);
        if (destDir.isDirectory() && !destDir.exists())
        {
            destDir.mkdir();
        }

        if (zFile.isEncrypted())
        {
            if (!StringUtils.hasLength(pwd))
            {
                throw new ZipException("文件已加密，需要解压密码，解压密码不能为空！");
            } else
            {
                zFile.setPassword(pwd.toCharArray());
            }
        }
        zFile.extractAll(dest);

        List<String> extractedFileList = new ArrayList<String>();

        List<FileHeader> headerList = zFile.getFileHeaders();
        if (headerList != null && headerList.size() > 0)
        {
            for (FileHeader fileHeader : headerList)
            {
                if (!fileHeader.isDirectory())
                {
                    extractedFileList.add(fileHeader.getFileName());
                }
            }
        }

        String[] extractedFiles = new String[extractedFileList.size()];
        extractedFileList.toArray(extractedFiles);
        return extractedFiles;
    }

    public static void main(String[] args)
    {
        //带压缩文件集合
        List<String> srcFiles = new ArrayList<String>();
        srcFiles.add("D:\\阅读书籍\\时间简史（插图本）.pdf");
        // srcFiles.add("C:\\Users\\Administrator\\Desktop\\TS平台部马毓凯901139\\恬静2.jpg");
        // srcFiles.add("C:\\Users\\Administrator\\Desktop\\TS平台部马毓凯901139\\恬静3.jpg");
        // srcFiles.add("C:\\Users\\Administrator\\Desktop\\TS平台部马毓凯901139\\恬静4.jpg");

        String destFile = "D:\\logs\\test.zip"; //压缩路径

        String password = "123"; //压缩包密码
        long fileSize = 1024 * 1024 * 3; //分卷大小（当前为最小值）

        try
        {
            //1.压缩
            System.out.println(zip(srcFiles, destFile, password, fileSize));

            //2.解压
            // String[] extractedFiles=unzip(destFile, "C:/test/a", passwd);
            // for (int i = 0; i < extractedFiles.length; i++) {
            //     System.out.println(extractedFiles[i]);
            // }

        } catch (ZipException e)
        {
            e.printStackTrace();
        }
    }
}
